﻿#include "websocketclient.h"

WebSocketClient::WebSocketClient(const QUrl &url,QObject *parent)
    : QObject(parent),
    m_url(url),
    WebSocket(new QWebSocket()),
    m_reconnectTimer(new QTimer(this)),
    m_reconnectAttempts(0),
    m_maxReconnectAttempts(3),
    m_reconnectInterval(5000) // 5 seconds
{
    // 连接相应的信号槽
    connect(WebSocket, &QWebSocket::connected, this, &WebSocketClient::slotConnected);
    connect(WebSocket, &QWebSocket::disconnected, this, &WebSocketClient::slotDisconnected);
    connect(WebSocket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &WebSocketClient::slotError);

    // 设置重连定时器
    m_reconnectTimer->setSingleShot(true);
    connect(m_reconnectTimer, &QTimer::timeout, this, &WebSocketClient::attemptReconnect);

    // 初始连接尝试
    m_bConnected = true;
    attemptReconnect();
}

WebSocketClient::~WebSocketClient()
{
    WebSocket->close();
    WebSocket->deleteLater();
    m_reconnectTimer->deleteLater();
}

// 连接成功
void WebSocketClient::slotConnected()
{
    qDebug()<<"Websocket connected successful";
    m_reconnectAttempts = 0;
    m_reconnectTimer->stop();
    connect(WebSocket, &QWebSocket::textMessageReceived, this, &WebSocketClient::slotRecvTextMsg);
    connect(WebSocket, &QWebSocket::binaryMessageReceived, this, &WebSocketClient::slotRecvBinaryMsg);
}

// 断开连接
void WebSocketClient::slotDisconnected()
{
    qDebug() << "WebSocket disconnected!";
    if(getConStatus()){
        if (m_reconnectAttempts < m_maxReconnectAttempts) {
            m_reconnectAttempts++;
            m_reconnectTimer->start(m_reconnectInterval);
        } else {
            m_reconnectAttempts=0;//重置次数
            m_bConnected=false;//标志设置为不可用
            qDebug() << "Max reconnect attempts reached, giving up.";
        }
    }
}

// 响应报错
void WebSocketClient::slotError(QAbstractSocket::SocketError error)
{
    switch(error){
        case QAbstractSocket::ConnectionRefusedError:// 连接被拒绝
        case QAbstractSocket::RemoteHostClosedError: // 远程主机关闭了连接
        case QAbstractSocket::HostNotFoundError: // 无法找到主机（DNS解析失败或主机不可达）
        case QAbstractSocket::SocketAccessError: // 套接字操作被操作系统阻止，因为缺乏适当的权限
        case QAbstractSocket::SocketAddressNotAvailableError: // 地址不可用
        {
            WebSocket->close();
            emit logout();
        }break;
        case QAbstractSocket::NetworkError: // 网络错误（套接字操作因网络故障而失败）
        case QAbstractSocket::SocketTimeoutError:{ // 连接超时（在指定的时间内没有成功建立连接）
            qDebug() << "attempting to reconnect...";
            m_reconnectTimer->stop();
            m_reconnectAttempts = 0;
            attemptReconnect();
        }break;
        default:
            qDebug() << "An unknown socket error occurred:" << error;
    }
}

void WebSocketClient::attemptReconnect()
{
    qDebug() << "Websocket connecting";
    WebSocket->open(m_url);
}

void WebSocketClient::close()
{
    m_bConnected=false;
    WebSocket->close();
}

// 发送Text类型的消息
void WebSocketClient::sendTextMsg(const QString &message)
{
    if(!getConStatus())
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running...";
        return;
    }
    //qDebug() << "send: " << message;
    WebSocket->sendTextMessage(message);
}

// 发送Binary类型的消息
void WebSocketClient::sendBinaryMsg(const QByteArray &data){
    if(!getConStatus())
    {
        qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running...";
        return;
    }
    WebSocket->sendBinaryMessage(data);
}
void WebSocketClient::sendBinaryMsg(QFile &file)
{
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << __FILE__ << __LINE__ << "Failed to" << __FUNCTION__ << ", it's not running...";
        return;
    }
    const int chunkSize = 4096; // 定义块大小，例如4KB
    QByteArray buffer(chunkSize, Qt::Uninitialized);
    qint64 bytesRead;
    while (getConStatus()) {
        if((bytesRead = file.read(buffer.data(), chunkSize)) > 0)
            WebSocket->sendBinaryMessage(buffer.mid(0, bytesRead)); // 发送读取到的块
        else
            break;
    }
    file.close();
}

// 返回服务器连接状态
bool WebSocketClient::getConStatus()
{
    return m_bConnected;
}

// 接受字符数据
void WebSocketClient::slotRecvTextMsg(const QString &message)
{
    qDebug()<<"-------------- WEBSOCKET DATA --------------";
    qDebug()<<"TYPE : text";
    qDebug()<<"FROM : SERVER";
    qDebug()<<"CONTENT : "<<message;
    qDebug()<<"---------------------------------------------";
    emit sigRecvTextMsg(message);
}

// 接受二进制数据
void WebSocketClient::slotRecvBinaryMsg(const QByteArray &message)
{
    qDebug()<<"-------------- WEBSOCKET DATA --------------";
    qDebug()<<"TYPE : Binary";
    qDebug()<<"FROM : SERVER";
    qDebug()<<"CONTENT : "<<message;
    qDebug()<<"---------------------------------------------";
    emit sigRecvBinaryMsg(message);
}

void WebSocketClient::setUrl(const QUrl &url){
    this->m_url=url;
}




